package com.asialjim.wechat.spring.config;

import com.asialjim.wechat.apiservice.AccessTokenService;
import com.asialjim.wechat.apiservice.ApiService;
import com.asialjim.wechat.apiservice.HttpMethod;
import com.asialjim.wechat.apiservice.SecondAccessTokenCache;
import com.asialjim.wechat.apiservice.constant.WeChatConstants;
import com.asialjim.wechat.apiservice.exception.WeChatApiException;
import com.asialjim.wechat.apiservice.executor.ApiExecutor;
import com.asialjim.wechat.apiservice.executor.ApiExecutorBuilder;
import com.asialjim.wechat.apiservice.impl.AccessTokenServiceImpl;
import com.asialjim.wechat.apiservice.impl.SecondAccessTokenCacheImpl;
import com.asialjim.wechat.core.bean.WeChatBean;
import com.asialjim.wechat.core.executor.WeChatApiExecutor;
import com.asialjim.wechat.database.DataBaseService;
import com.asialjim.wechat.executor.WeChatApiExecutorImpl;
import com.asialjim.wechat.spring.bean.WeChatBeanSelector;
import com.asialjim.wechat.spring.config.swagger.WeChatSwaggerConfig;
import com.asialjim.wechat.spring.filter.WeChatFilter;
import lombok.var;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.mybatis.spring.annotation.MapperScan;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.*;

/**
 * <h1><em>ASIAL JIM JAVA DOC</em></h1><hr/>
 * <h2>CLASS DESCRIPTION <i>[ NAME: WeChatConfig ]</i></h2><strong>
 * <p> we-chat configuration
 * </strong><p><p><em>Copyright &copy; Asial Jim Co., LTD</em><hr/>
 *
 * @author Asial Jim &nbsp;&nbsp; <span>Email:<a href="mailto:asialjim@hotmail.com">asialjim@hotmail.com</a> &nbsp;&nbsp; <a href="asialjim@qq.com">asialjim@qq.com</a></span>
 * @version 1.0.0
 * @since 2021/3/11   &nbsp;&nbsp; JDK 8
 */
@Configuration
@MapperScan("com.asialjim.wechat.mapper")
@WeChatBeanSelector(beanClass = {ApiService.class, WeChatBean.class},basePackage = "com.asialjim.wechat")
public class WeChatConfig {

    @Bean
    public FilterRegistrationBean<WeChatFilter> filterFilterRegistrationBean(){
        FilterRegistrationBean<WeChatFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WeChatFilter());
        bean.addUrlPatterns("/*");
        bean.setName("weChatFilter");
        bean.setOrder(1);
        return bean;
    }

    @Bean
    public Docket docket(){
        return new WeChatSwaggerConfig().createRestApi();
    }

    @Bean
    @ConditionalOnMissingBean(AccessTokenService.class)
    public AccessTokenService accessTokenService(WeChatApiConfigProperties properties, RedissonClient redissonClient, SecondAccessTokenCache accessTokenCache, DataBaseService dataBaseService){
        properties = weChatApiConfigProperties(properties);
        var service = new AccessTokenServiceImpl();
        service.setDomain(properties.getDomain());
        HttpHost httpProxy = StringUtils.isNotBlank(properties.getHostname()) && Objects.nonNull(properties.getPort()) ? new HttpHost(properties.getHostname(),properties.getPort()) : null;
        service.setHttpProxy(httpProxy);
        service.setRedissonClient(redissonClient);
        service.setSecondAccessTokenCache(accessTokenCache);
        service.setDataBaseService(dataBaseService);
        return service;
    }

    @Bean
    public RedissonClient redissonClient(LettuceConnectionFactory factory){
        Config config = new Config();
        var clusterConfiguration = factory.getClusterConfiguration();
        if (Objects.isNull(clusterConfiguration)){
            String hostName = factory.getHostName();
            int port = factory.getPort();
            config.useSingleServer().setAddress("redis://"+hostName+":"+port);
            return Redisson.create(config);
        }

        var clusterServersConfig = config.useClusterServers();
        clusterConfiguration.getClusterNodes().forEach(node ->clusterServersConfig.addNodeAddress("redis://"+node.getHost()+":"+node.getPort()));

        return Redisson.create(config);
    }

    @Bean(initMethod = "init")
    public SecondAccessTokenCache secondAccessTokenCache(RedissonClient client){
        var cache = new SecondAccessTokenCacheImpl();
        cache.setRedisson(client);
        return cache;
    }

    @Bean
    public WeChatApiExecutor weChatApiExecutor(AccessTokenService accessTokenService,WeChatApiConfigProperties properties){
        properties = weChatApiConfigProperties(properties);
        String applicationDomain = properties.getApplicationDomain();
        if (StringUtils.isBlank(applicationDomain)){
            WeChatApiException.cast("999999","未设置应用域名","application domain unset");
        }
        var executor = new WeChatApiExecutorImpl();
        executor.setAccessTokenService(accessTokenService);
        executor.setDomain(properties.getDomain());

        String domain = StringUtils.isBlank(properties.getDomain()) ? WeChatConstants.WeChatApiDomain.COMMON_DOMAIN : properties.getDomain();
        HttpHost httpProxy = StringUtils.isNotBlank(properties.getHostname()) && Objects.nonNull(properties.getPort()) ? new HttpHost(properties.getHostname(),properties.getPort(),properties.getScheme()) : null;

        var executorMap = new HashMap<HttpMethod, ApiExecutor>();
        executorMap.put(HttpMethod.GET, ApiExecutorBuilder.build(HttpMethod.GET,httpProxy,domain,properties.getTempDirFilePath()));
        executorMap.put(HttpMethod.POST,ApiExecutorBuilder.build(HttpMethod.POST,httpProxy,domain,properties.getTempDirFilePath()));

        executor.setExecutorMap(executorMap);
        executor.setHttpProxy(httpProxy);
        executor.setTempFilePath(properties.getTempDirFilePath());
        executor.setWeChatApiMaxRetry(properties.getWeChatApiMaxRetry());
        executor.setApplicationDomain(applicationDomain);
        return executor;
    }

    private WeChatApiConfigProperties weChatApiConfigProperties(WeChatApiConfigProperties properties){
        if (Objects.isNull(properties)){
            properties = new WeChatApiConfigProperties();
        }

        if (StringUtils.isBlank(properties.getDomain())){
            properties.setDomain(WeChatConstants.WeChatApiDomain.COMMON_DOMAIN);
        }

        if (StringUtils.isBlank(properties.getTempDirFilePath())){
            properties.setTempDirFilePath(WeChatApiConfigProperties.DEFAULT_TEMP_FILE_PATH);
        }

        if (Objects.isNull(properties.getWeChatApiMaxRetry())){
            properties.setWeChatApiMaxRetry(3);
        }

        if (StringUtils.isBlank(properties.getScheme())){
            properties.setScheme("http");
        }

        return properties;
    }
}